package com.xu.cloud.common.config;

import com.xu.cloud.common.conditional.ConditionalOnAnnotationStatement;
import com.xu.cloud.common.thread.ThreadPoolProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.AllNestedConditions;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 线程池配置类
 *
 * @author xuguan
 * @since 2023/11/10
 */
@Configuration
@ConditionalOnAnnotationStatement({EnableAsync.class})
@EnableConfigurationProperties(value = ThreadPoolProperties.class)
public class ThreadPoolConfig {
    private static final Logger log = LoggerFactory.getLogger(ThreadPoolConfig.class);

    @Bean("threadPoolExecutor")
    @Conditional(NameAndTypeMissingConditions.class)
    public ThreadPoolExecutor threadPoolExecutor(ThreadPoolProperties threadPoolProperties) {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                threadPoolProperties.getCorePoolSize(),
                threadPoolProperties.getMaxPoolSize(),
                60,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(threadPoolProperties.getQueueCapacity()),
                new CustomizableThreadFactory("async-threadPool-executor-"),
                new ThreadPoolExecutor.AbortPolicy()
        );

        log.info("threadPoolExecutor created successfully, corePoolSize[{}], maximumPoolSize[{}]",
                threadPoolExecutor.getCorePoolSize(), threadPoolExecutor.getMaximumPoolSize());
        return threadPoolExecutor;
    }

    /**
     * 组合条件注解, 当缺少指定名称的bean且缺少指定类型的bean时才生效
     */
    public static class NameAndTypeMissingConditions extends AllNestedConditions {
        public NameAndTypeMissingConditions() {
            super(ConfigurationPhase.REGISTER_BEAN);
        }

        @ConditionalOnMissingBean(name = {"threadPoolExecutor"})
        public static class NameMissing {
        }

        @ConditionalOnMissingBean(value = {ThreadPoolExecutor.class})
        public static class TypeMissing {
        }
    }

}
